package com.iteaj.iot.plc.omron;

import cn.hutool.core.collection.CollectionUtil;
import com.iteaj.iot.Message;
import com.iteaj.iot.plc.PlcException;
import com.iteaj.iot.plc.PlcProtocolType;
import com.iteaj.iot.plc.ReadAddress;
import com.iteaj.iot.plc.WriteAddress;
import com.iteaj.iot.plc.AddressType;

import java.util.List;

public class OmronMessageBody implements Message.MessageBody{

    private byte[] message;

    private static int bitLimit = 1985;
    private static int wordLimit = 500;
    private static int batchLimit = 89; // 批量读取不连续的点位数量限制

    protected OmronMessageBody(byte[] message) {
        this.message = message;
    }

    /**
     * 连续读取多个点位
     * @param address
     * @return
     */
    public static OmronMessageBody buildReadRequestBody(ReadAddress address) {
        if(address == null) {
            throw new PlcException("请指定要读取的点位信息", PlcProtocolType.Omron);
        }

        OmronAddressResolver resolver = OmronAddressResolver.ParseFrom(address.getAddress(), address.getLength());
        byte[] message = new byte[8];
        // 批量读取存储区数据
        message[0] = message[1] = 0x01;

        if(address.getType() == AddressType.Bit) {
            message[2] = resolver.getBitCode();
            // 读取长度限制校验
            if(address.getLength() > bitLimit) {
                throw new PlcException("批量位读取长度(连续)超出限制["+bitLimit+"]", PlcProtocolType.Omron);
            }
        } else {
            message[2] = resolver.getWordCode();
            // 读取长度限制校验
            if(address.getLength() > wordLimit) {
                throw new PlcException("批量字读取长度(连续)超出限制["+wordLimit+"]", PlcProtocolType.Omron);
            }
        }

        message[3] = (byte) (resolver.getAddressStart() / 16 / 256);
        message[4] = (byte) (resolver.getAddressStart() / 16 % 256);
        message[5] = (byte) (resolver.getAddressStart() % 16);
        message[6] = (byte) (resolver.getLength() / 256); // 长度
        message[7] = (byte) (resolver.getLength() % 256);

        return new OmronMessageBody(message);
    }

    /**
     * 批量读取(不连续的地址)
     * @param batchAddress
     * @return
     */
    public static OmronMessageBody buildReadRequestBody(List<ReadAddress> batchAddress) {
        if(CollectionUtil.isEmpty(batchAddress)) {
            throw new PlcException("请指定要读取的点位信息", PlcProtocolType.Omron);
        }

        if(batchAddress.size() > batchLimit) {
            throw new PlcException("批量读取长度(不连续)超出限制["+batchLimit+"]", PlcProtocolType.Omron);
        }

        byte[] message = new byte[2 + 4 * batchAddress.size()];
        // 批量读取存储区数据
        message[0] = 0x01; message[1] = 0x04;

        for(int i=0; i<batchAddress.size(); i++) {
            ReadAddress address = batchAddress.get(i);
            OmronAddressResolver resolver = OmronAddressResolver.ParseFrom(address.getAddress(), (short) 1);

            message[2 + 4 * i] = resolver.getWordCode();
            message[3 + 4 * i] = (byte)(resolver.getAddressStart() / 16 / 256);
            message[4 + 4 * i] = (byte)(resolver.getAddressStart() / 16 % 256);
            message[5 + 4 * i] = (byte)(resolver.getAddressStart() % 16);
        }

        return new OmronMessageBody(message);
    }

    public static OmronMessageBody buildWriteRequestBody(WriteAddress writeAddress) {
        int length = writeAddress.getData().length;
        byte[] message = new byte[8 + length];
        OmronAddressResolver resolver = OmronAddressResolver.ParseFrom(writeAddress.getAddress(), (short) 0);

        message[0] = 0x01; // 写入
        message[1] = 0x02;

        if (writeAddress.getType() == AddressType.Bit) {
            message[2] = resolver.getBitCode();

            message[6] = (byte) (length / 256);
            message[7] = (byte) (length % 256);
        } else {
            message[2] = resolver.getWordCode();

            message[6] = (byte) (length / 2 / 256);
            message[7] = (byte) (length / 2 % 256);
        }

        message[3] = (byte) (resolver.getAddressStart() / 16 / 256);
        message[4] = (byte) (resolver.getAddressStart() / 16 % 256);
        message[5] = (byte) (resolver.getAddressStart() % 16);

        System.arraycopy(writeAddress.getData(), 0, message, 8, length);
        return new OmronMessageBody(message);
    }

    @Override
    public byte[] getMessage() {
        return this.message;
    }
}
